package edu.asu.sefcom.extract.profile.data;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.helper.StringUtil;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Neo4jConnectorBrowser {

	public enum MyRelationshipTypes implements
			org.neo4j.graphdb.RelationshipType {

		Posts, Follows, FollowsBack, MemberOf

	}

	public static void main(String args[]) throws FileNotFoundException {

//		Properties properties = new Properties();
//		try {
//			properties.load(new FileInputStream("config/app.properties"));
//		} catch (IOException e) {
//		}
//		String dbDir = "" + properties.getProperty("edu.asu.sefcom.extract.profile.database.dir");
//		EmbeddedGraphDatabase graphDB = new EmbeddedGraphDatabase(dbDir);

		Neo4jConnectorBrowser neo4jb=new Neo4jConnectorBrowser();
		
//		List<Node> nodes= neo4jb.getNodesbyType(neo4jb.graphDB, "User");
//		System.out.println(nodes.size());
//		long node= neo4jb.getNodebyName(neo4jb.graphDB, "90h");
//		System.out.println(node);
//		String prop=""+neo4jb.graphDB.getNodeById(node).getProperty("Type");
//		System.out.println(prop);
		neo4jb.graphDB.shutdown();
	}
	
	Logger logger = Logger.getLogger(Neo4jConnectorBrowser.class);

	GraphDatabaseService graphDB;

	public Neo4jConnectorBrowser() {
		Properties properties = new Properties();
		try {
			properties.load(new FileInputStream("config/app.properties"));
		} catch (IOException e) {
		}
		String dbDir = "" + properties.getProperty("edu.asu.sefcom.extract.profile.database.dir");
		graphDB = new EmbeddedGraphDatabase(dbDir);
	}

	private Object translate(String article) throws Exception {
		String ret = "";
		try {
			ret = GoogleTranslate.translate(article);
		} catch (Exception e) {
			if (e.getLocalizedMessage().contains("404")) {
				logger.warn("404 thrown...");
				Thread.currentThread().sleep(3000);
			} else {
				Thread.currentThread().sleep(1000);
			}
			System.exit(0);
		}

		return ret;
	}

	private Object removeHtml(String article) {
		String ret = article.replaceAll("<br>", "");
		ret = ret.replaceAll("\\<.*?>", "");
		ret = ret.replaceAll("\\.*?>", "");
		return Jsoup.parse(ret).text();
	}

	public List<Node> getNodesbyType(GraphDatabaseService graphDB, String type1) {
		System.out.println("in node by type");
		List<Node> list1=new ArrayList<Node>();
		Transaction tx = graphDB.beginTx();
		try {
			Iterable<Node> nodes = graphDB.getAllNodes();

			Iterator itr = nodes.iterator();
			
			while (itr.hasNext()) {
				Node node = (Node) itr.next();
				Iterator<String> keysItr = node.getPropertyKeys().iterator();
				while (keysItr.hasNext()) {
					String key = keysItr.next();
					if (key.equalsIgnoreCase("Type")) {
						if ((""+node.getProperty(key)).equalsIgnoreCase(type1)) {
							list1.add(node);
						}
					}
				}
			}
			tx.success();
		} finally {
			tx.finish();
		}
		return list1;
	}
	public static long getNodebyName(GraphDatabaseService graphDB, String UName) {
		System.out.println("in node by name");
		Transaction tx = graphDB.beginTx();
		Node resultNode = null;
		try {
			Iterable<Node> Nodes = graphDB.getAllNodes();

			Iterator itr = graphDB.getAllNodes().iterator();

			while (itr.hasNext()) {
				Node node = (Node) itr.next();
				Iterator<String> keysItr = node.getPropertyKeys().iterator();
				while (keysItr.hasNext()) {
					String key = keysItr.next();
					if (key.equals("Name")) {
						if ((node.getProperty("Name")).equals(UName)) {
							resultNode = node;
						}
					}
				}
			}
			tx.success();
		} finally {
			tx.finish();
		}
		if (resultNode == null)
			return 0;
		else
			return resultNode.getId();

	}

	public Node createUserNode(String name, String created, String updated) {
		Node userNode = null;
		String name1 = name.length() > 17 ? name.substring(0, 17) : name;
		name = Jsoup.parse(name).text();
		if (removenoise(name)) {
			return null;
		}
		long ID = getNodebyName(this.graphDB, name);

		if (ID == 0) {
			Transaction tx = graphDB.beginTx();
			try {
				userNode = graphDB.createNode();
				userNode.setProperty("Type", "User");
				userNode.setProperty("Name", name1);
				userNode.setProperty("ICQ_UIN", "Empty");
				userNode.setProperty("Email", "Empty");
				userNode.setProperty("Follows", "Empty");
				userNode.setProperty("FollowsBack", "Empty");
				if (null != created) {
					Date cre = TranslateUtils.getDate(created);
					Date up = TranslateUtils.getDate(updated);
					userNode.setProperty("Created", cre);
					userNode.setProperty("Updated", up);
				}
				System.out.println("Create Node for User:" + name);
				tx.success();
			} finally {
				tx.finish();
			}
		}

		return userNode;
	}

	private boolean removenoise(String name) {
		boolean test = (name.contains("comment") || name.startsWith("comment")
				|| name.startsWith("Comment") || name.startsWith("Current"));
		return test;
	}

	public void storeUserCommData(List<String> dates, List<String> groups,
			String userName) {
		long userNodeID = getNodebyName(graphDB, "" + removeHtml(userName));
		logger.warn("userNodeID : " + userNodeID);
		logger.warn("commName- : " + groups);
			createCommunity(graphDB, null, groups, userNodeID);
			updateUser(userNodeID,dates);
	}
	
	private void updateUser(long userNodeID, List<String> dates) {
		Node userNode = graphDB.getNodeById(userNodeID);
		Transaction tx = graphDB.beginTx();
		try {
			Date cre = TranslateUtils.getDate(dates.get(0));
			Date up = TranslateUtils.getDate(dates.get(1));
				userNode.setProperty("Created", cre);
				userNode.setProperty("Updated", up);
				
			tx.success();
		} finally {
			tx.finish();
		}
	}

	public void storeCommData(List<String> dates, List<String> users,
			String commName) {
		logger.warn("userNames- : " + users);
		long commNodeID = getNodebyName(graphDB, "" + removeHtml(commName));
		Node commNode = graphDB.getNodeById(commNodeID);
		for(String name:users){
			Node userNode = createUserNode(name, null, null);
			
			Transaction tx = graphDB.beginTx();
			userNode.createRelationshipTo(commNode,
					MyRelationshipTypes.MemberOf);
			tx.success();
		}
		updateComm(commNode,dates);
	}

	private void updateComm(Node community, List<String> dates) {
		Transaction tx = graphDB.beginTx();
		Date cre = TranslateUtils.getDate(dates.get(0));
		Date up = TranslateUtils.getDate(dates.get(1));
		try {
		community.setProperty("Created", cre.toString());
		community.setProperty("Updated", up.toString());
		} finally {
			tx.finish();
		}
		
	}

	private void createCommunity(GraphDatabaseService graphDB,
			List<String> dates, List<String> groups, long userNodeID) {
		Node community;
		Transaction tx = graphDB.beginTx();

		try {
			for (String name : groups) {
				if (!checkIfExistsComm(name)) {
					community = graphDB.createNode();
					community.setProperty("Type", "Comm");
					community.setProperty("Name", name);
					if (null != dates) {
						Date cre = TranslateUtils.getDate(dates.get(0));
						Date up = TranslateUtils.getDate(dates.get(1));
						community.setProperty("Created", cre.toString());
						community.setProperty("Updated", up.toString());
					}
					System.out.println("Create Node for Comm:" + name);
					Node user = graphDB.getNodeById(userNodeID);
					user.createRelationshipTo(community,
							MyRelationshipTypes.MemberOf);
					tx.success();
				}

			}
		} finally {
			tx.finish();
		}

	}

	private boolean checkIfExistsComm(String name) {
		long ID = getNodebyName(this.graphDB, name);
		return ID == 0 ? false : true;
	}

}
